﻿using Shop.Core.Enums;
using Shop.Core.Helper;
using Shop.Core.Repository;
using Shop.Core.Share;
using Shop.IServices;
using Shop.Model.Dto.Mine;
using Shop.Model.Entity.Order;
using Shop.Model.Entity.System;
using Shop.Model.Entity.Use;
using Shop.Model.View.Mine;
using SqlSugar;

namespace Shop.Services;

public class MineDetailService : AbstractService, IMineDetailService
{
    private readonly RepositoryBase<UseUser> _userRepository;
    private readonly RepositoryBase<UserWalletLog> _wallLogRepository;
    private readonly RepositoryBase<UseUserRelation> _userRelationRepository;
    private readonly RepositoryBase<SysConstantEntity> _constantRepository;
    private readonly RepositoryBase<UserWallet> _walletRepository;
    private readonly RepositoryBase<UseCardEntity> _cardRepository;
    private readonly RepositoryBase<UseDrawMoneyEntity> _drawMoneyRepository;
    private readonly RepositoryBase<Orders> _orderRepository;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="userRepository"></param>
    /// <param name="wallLogRepository"></param>
    /// <param name="userRelationRepository"></param>
    /// <param name="constantRepository"></param>
    /// <param name="walletRepository"></param>
    /// <param name="cardRepository"></param>
    /// <param name="drawMoneyRepository"></param>
    /// <param name="orderRepository"></param>
    public MineDetailService(RepositoryBase<UseUser> userRepository,
        RepositoryBase<UserWalletLog> wallLogRepository,
        RepositoryBase<UseUserRelation> userRelationRepository,
        RepositoryBase<SysConstantEntity> constantRepository,
        RepositoryBase<UserWallet> walletRepository,
        RepositoryBase<UseCardEntity> cardRepository,
        RepositoryBase<UseDrawMoneyEntity> drawMoneyRepository,
        RepositoryBase<Orders> orderRepository)
    {
        _userRepository = userRepository;
        _wallLogRepository = wallLogRepository;
        _userRelationRepository = userRelationRepository;
        _constantRepository = constantRepository;
        _walletRepository = walletRepository;
        _cardRepository = cardRepository;
        _drawMoneyRepository = drawMoneyRepository;
        _orderRepository = orderRepository;
    }

    /// <summary>
    /// 我的钱包日志
    /// </summary>
    /// <param name="uId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<MyWalletListVo>> MyWalletList(long uId, MyWalletListDto dto)
    {
        var records = 0;
        var userInfo = _userRepository.Where(x => x.Id == uId).First();
        var data = _wallLogRepository
            .Where(x => x.UserId == uId)
            .WhereIF(dto.Type == 1,
                x => x.State == 1 && (x.Action == (int)WalletSourceTypes.Distribution ||
                                      x.Action == (int)WalletSourceTypes.Dividend ||
                                      x.Action == (int)WalletSourceTypes.Prize))
            .WhereIF(dto.Type == 2,
                x => x.State == 0 && (x.Action == (int)WalletSourceTypes.Distribution ||
                                      x.Action == (int)WalletSourceTypes.Dividend ||
                                      x.Action == (int)WalletSourceTypes.Prize))
            .WhereIF(dto.Type == 3, x => x.Action == (int)WalletSourceTypes.Pay && x.State == 1)
            .WhereIF(dto.Type == 4, x => x.Action == (int)WalletSourceTypes.Tocash && x.State == 1)
            .WhereIF(dto.Type == 5, x => x.Action == (int)WalletSourceTypes.Tocash && x.State == 0)
            .WhereIF(dto.Type == 6, x => x.Action == (int)WalletSourceTypes.Refund && x.State == 1)
            .OrderByDescending(x => x.CreateTime)
            .Select(x => new MyWalletListVo()
            {
                Name = x.Action == (int)WalletSourceTypes.Distribution ? "佣金收入" :
                    x.Action == (int)WalletSourceTypes.Dividend ? "佣金收入" :
                    x.Action == (int)WalletSourceTypes.Prize ? "佣金收入" :
                    x.Action == (int)WalletSourceTypes.Pay ? "余额支付" :
                    x.Action == (int)WalletSourceTypes.Tocash ? "余额提现" :
                    x.Action == (int)WalletSourceTypes.Refund ? "订单退款" : 
                    x.Action == 6 ? "后台调整-增加" : 
                    x.Action == 7 ? "后台调整-减少" : "未知",
                Time = x.CreateTime,
                WallState = x.State == -1 ? "失败" : x.State == 0 ? "处理中" : "成功",
                State = x.Action == (int)WalletSourceTypes.Distribution ? 1 :
                    x.Action == (int)WalletSourceTypes.Dividend ? 1 :
                    x.Action == (int)WalletSourceTypes.Prize ? 1 :
                    x.Action == (int)WalletSourceTypes.Pay ? -1 :
                    x.Action == (int)WalletSourceTypes.Tocash ? -1 : 1,
                Money = x.Amount,
                Action = x.Action,
                SourceOrder = x.SourceOrder
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        foreach (var item in data)
        {
            var ordCode = "";
            if (item.Action == 1 || item.Action == 3 || item.Action == 9)
            {
                ordCode = _orderRepository.Where(x => x.Id == item.SourceOrder).Select(x => x.Code).First();
            }
            switch (item.Action)
            {
                case 1:
                    item.Code = $"订单编号 {ordCode}";
                    break;
                case 2:
                    item.Code = $"{userInfo.Nickname}";
                    break;
                case 3:
                    item.Code = $"订单编号 {ordCode}";
                    break;
                case 4:
                    item.Code = "奖励";
                    break;
                case 5:
                    item.Code = "分红";
                    break;
                case 6:
                    item.Code = "后台调整";
                    break;
                case 7:
                    item.Code = "后台调整";
                    break;
                case 9:
                    item.Code = $"订单编号 {ordCode}";
                    break;
                default:
                    item.Code = "";
                    break;
            }
        }

        return new PageModel<MyWalletListVo>(dto, data, records);
    }

    /// <summary>
    /// 我的收益明细列表
    /// </summary>
    /// <param name="uId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<MyEarningsListVo>> MyEarningsList(long uId, MyEarningsListDto dto)
    {
        var records = 0;
        var data = _wallLogRepository.Queryable<UserWalletLog, Orders, UseUser>((t1, t2, t3) => new object[]
            {
                JoinType.Left, t1.SourceOrder == t2.Id,
                JoinType.Left, t2.UserId == t3.Id
            })
            .Where((t1, t2, t3) => t1.UserId == uId && t1.State == 1)
            .WhereIF(dto.Type == 0, (t1, t2, t3) =>
                t1.Action == (int)WalletSourceTypes.Distribution || t1.Action == (int)WalletSourceTypes.Dividend ||
                t1.Action == (int)WalletSourceTypes.Prize)
            .WhereIF(dto.Type == 1, (t1, t2, t3) => t1.Action == (int)WalletSourceTypes.Distribution)
            .WhereIF(dto.Type == 2, (t1, t2, t3) => t1.Action == (int)WalletSourceTypes.Prize)
            .WhereIF(dto.Type == 3, (t1, t2, t3) => t1.Action == (int)WalletSourceTypes.Dividend)
            .WhereIF(dto.TimeType == 1 && dto.Time != null,
                (t1, t2, t3) => t1.FinishTime >= dto.Time.Value.Date && t1.FinishTime < dto.Time.Value.AddDays(1).Date)
            .WhereIF(dto.TimeType == 2 && dto.Time != null,
                (t1, t2, t3) => t1.FinishTime >= dto.Time.Value && t1.FinishTime < dto.Time.Value.AddMonths(1).Date)
            .OrderByDescending((t1, t2, t3) => t1.FinishTime)
            .Select((t1, t2, t3) => new MyEarningsListVo
            {
                LName = t1.Action == (int)WalletSourceTypes.Distribution ? "销售佣金" :
                    t1.Action == (int)WalletSourceTypes.Prize ? "销售分红" : "定期分红",
                Time = t1.CreateTime,
                UImg = t3.Head,
                UName = t3.Nickname,
                OId = t2.Id,
                Money = t1.Amount
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        return new PageModel<MyEarningsListVo>(dto, data, records);
    }

    /// <summary>
    /// 我的收益明细数值
    /// </summary>
    /// <param name="uId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<MyEarningsStatisticsVo> MyEarningsStatistics(long uId, MyEarningsListDto dto)
    {
        var myEarningsStatisticsVo = new MyEarningsStatisticsVo();
        var data = _wallLogRepository
            .Where(x => x.UserId == uId && x.State == 1)
            .WhereIF(dto.Type == 0, x =>
                x.Action == (int)WalletSourceTypes.Distribution || x.Action == (int)WalletSourceTypes.Dividend ||
                x.Action == (int)WalletSourceTypes.Prize)
            .WhereIF(dto.Type == 1, x => x.Action == (int)WalletSourceTypes.Distribution)
            .WhereIF(dto.Type == 2, x => x.Action == (int)WalletSourceTypes.Prize)
            .WhereIF(dto.Type == 3, x => x.Action == (int)WalletSourceTypes.Dividend)
            .WhereIF(dto.TimeType == 1 && dto.Time != null,
                x => x.FinishTime >= dto.Time.Value.Date && x.FinishTime < dto.Time.Value.AddDays(1).Date)
            .WhereIF(dto.TimeType == 2 && dto.Time != null,
                x => x.FinishTime >= dto.Time.Value && x.FinishTime < dto.Time.Value.AddMonths(1).Date)
            .ToList();
        myEarningsStatisticsVo.SumBrokerage =
            data.Where(x => x.Action == (int)WalletSourceTypes.Distribution).Sum(x => x.Amount);
        myEarningsStatisticsVo.SumSell =
            data.Where(x => x.Action == (int)WalletSourceTypes.Prize).Sum(x => x.Amount);
        myEarningsStatisticsVo.SumTerminal =
            data.Where(x => x.Action == (int)WalletSourceTypes.Dividend).Sum(x => x.Amount);
        myEarningsStatisticsVo.SumEarnings = myEarningsStatisticsVo.SumBrokerage + myEarningsStatisticsVo.SumSell +
                                             myEarningsStatisticsVo.SumTerminal;
        return myEarningsStatisticsVo;
    }

    /// <summary>
    /// 我的顾客会员数据
    /// </summary>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<MyCustomerDataVo> MyCustomerData(long uId)
    {
        var myCustomerDataVo = new MyCustomerDataVo();
        var userInfo = _userRepository.Where(x => x.Id == uId).First();
        myCustomerDataVo.Grade = userInfo.Grade;
        myCustomerDataVo.Consume = userInfo.BuyCount;
        myCustomerDataVo.AddUp = userInfo.Points;
        var memberInfo = _userRepository.Where(x => x.SuperiorUser == uId).ToList();
        myCustomerDataVo.Member = memberInfo.Count();
        var mId = memberInfo.Select(x => x.Id).ToList();
        myCustomerDataVo.Team = _userRelationRepository.Where(x => x.Ancestor == uId).Count();
        var polt = _userRelationRepository.Queryable<UseUser, UseUserRelation>((t1, t2) => new object[]
            {
                JoinType.Left, t1.Id == t2.Ancestor
            })
            .Where((t1, t2) => t1.SuperiorUser == uId)
            .GroupBy((t1, t2) => t1.Id)
            .Select((t1, t2) => new
            {
                ancestor = t1.Id,
                count = SqlFunc.AggregateCount(t2.Descendant) + 1
            })
            .ToList();
        polt = polt.OrderByDescending(x => x.count).ToList();
        if (polt.Count > 0)
        {
            polt.RemoveAt(0);
            myCustomerDataVo.Plot = polt.Sum(x => x.count);
        }
        else
            myCustomerDataVo.Plot = 0;

        myCustomerDataVo.Earnings = _wallLogRepository
            .Where(x => x.UserId == uId && x.FinishTime >= DateTime.Now.Date &&
                        x.FinishTime < DateTime.Now.AddDays(1).Date && x.State == 1)
            .Where(x => x.Action == (int)WalletSourceTypes.Distribution ||
                        x.Action == (int)WalletSourceTypes.Prize ||
                        x.Action == (int)WalletSourceTypes.Dividend)
            .Sum(x => x.Amount);
        var users = memberInfo.OrderByDescending(x => x.Points).ToList();
        if (users.Count < 2)
            myCustomerDataVo.PlotOrd = 0;
        else
        {
            users.RemoveAt(0);
            myCustomerDataVo.PlotOrd = users.Sum(x => x.Points);
        }

        return myCustomerDataVo;
    }

    /// <summary>
    /// 我的顾客会员列表
    /// </summary>
    /// <param name="uId"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<MyCustomerListVo>> MyCustomerList(long uId, MyCustomerListDto dto)
    {
        var records = 0;
        var data = _userRepository
            .Where(x => x.SuperiorUser == uId)
            .WhereIF(!string.IsNullOrEmpty(dto.Name), x => x.Nickname.Contains(dto.Name))
            .WhereIF(dto.Code.HasValue, x => x.Code == dto.Code)
            .WhereIF(dto.Grade == 1, x => x.Grade == 0)
            .WhereIF(dto.Grade == 2, x => x.Grade == 1)
            .WhereIF(dto.Grade == 3, x => x.Grade == 2)
            .WhereIF(dto.Grade == 4, x => x.Grade == 3)
            .OrderBy("CreatTime DESC, Id")
            .Select(x => new MyCustomerListVo()
            {
                Id = x.Id,
                Code = x.Code,
                Name = x.Nickname,
                Grade = x.Grade,
                Img = x.Head,
                Time = x.CreatTime,
                Tele = x.Tele
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        return new PageModel<MyCustomerListVo>(dto, data, records);
    }

    /// <summary>
    /// 提现信息
    /// </summary>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<UserBalanceVo> UserBalance(long uId)
    {
        var userBalanceVo = new UserBalanceVo();
        var constantKey = new List<string>
        {
            "drawings_procedure",
            "drawings_low",
            "drawings_wechat_high",
            "drawings_clip_high",
            "drawings_wechat_isOpen",
            "drawings_clip_isOpen"
        };
        var constant = _constantRepository.Where(x => constantKey.Contains(x.Key)).ToList();
        foreach (var item in constant)
        {
            switch (item.Key)
            {
                case "drawings_procedure":
                    userBalanceVo.Procedure = decimal.Parse(item.Value);
                    break;
                case "drawings_low":
                    userBalanceVo.DrawingsLow = int.Parse(item.Value);
                    break;
                case "drawings_wechat_high":
                    userBalanceVo.DrawingsWechatHigh = int.Parse(item.Value);
                    break;
                case "drawings_clip_high":
                    userBalanceVo.DrawingsClipHigh = int.Parse(item.Value);
                    break;
                case "drawings_wechat_isOpen":
                    userBalanceVo.DrawingsWechatIsOpen = bool.Parse(item.Value);
                    break;
                case "drawings_clip_isOpen":
                    userBalanceVo.DrawingsClipIsOpen = bool.Parse(item.Value);
                    break;
                default:
                    return Problem("常量参数错误");
            }
        }

        userBalanceVo.Balance = _walletRepository.Where(x => x.UserId == uId).Select(x => x.Balance).First();
        return userBalanceVo;
    }

    
    /// <summary>
    /// 用户提现
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult Drawings(DrawingsDto dto, long uId)
    {
        var useInfo = _userRepository.Where(x => x.Id == uId).First();
        if (useInfo == null) return Problem("用户不存在");
        if (!useInfo.WithdrawalPassword.Equals(CommonHelper.Md5For32(dto.Pass)))
            return Problem("支付密码错误");
        var userBalance = UserBalance(uId);
        if (userBalance.Data.DrawingsLow > dto.Amount) return Problem("小于最低提现金额");
        var startTime = DateTime.Now.Date;
        var endTime = DateTime.Now.Date.AddDays(1);
        var userDrawMoney = _drawMoneyRepository.Where(x => x.User == uId)
            .Where(x => x.FoundTime >= startTime && x.FoundTime < endTime).ToList();
        if (userDrawMoney.Count > 0) return Problem("每日提现次数为1次，请明日重新发起提现");
        if (dto.Type == 1)
        {
            if (!userBalance.Data.DrawingsWechatIsOpen) return Problem("提现到微信尚未开启");
            if (dto.Amount > userBalance.Data.DrawingsWechatHigh) return Problem("大于最高提现金额");
        }
        else if (dto.Type == 2)
        {
            if (!userBalance.Data.DrawingsClipIsOpen) return Problem("提现到银行卡尚未开启");
            if (dto.Amount > userBalance.Data.DrawingsClipHigh) return Problem("大于最高提现金额");
            if (!dto.Card.HasValue) return Problem("银行卡不可为空");
            var cardInfo = _cardRepository.Where(x => x.Id == dto.Card && x.IsValid == true).First();
            if (cardInfo == null) return Problem("银行卡信息不存在");
            if (cardInfo.User != uId) return Problem("用户信息不匹配");
        }
        else
            return Problem("提现类型错误");

        if (dto.Amount > userBalance.Data.Balance) return Problem("钱包余额不足");
        var procedure = dto.Amount * userBalance.Data.Procedure;
        var walletInfo = _walletRepository.Where(x => x.UserId == uId).First();
        walletInfo.Balance -= dto.Amount;
        var walletLogInfo = new UserWalletLog
        {
            UserId = uId,
            Action = (int)WalletSourceTypes.Tocash,
            State = 0,
            Title = $"余额提现:{dto.Amount}元",
            Procedure = procedure,
            Amount = dto.Amount
        };
        var walletLogId = _wallLogRepository.InsertReturnBigIdentity(walletLogInfo);
        _walletRepository.Update(walletInfo);
        var useDrawMoney = new UseDrawMoneyEntity()
        {
            User = uId,
            WalletLog = walletLogId,
            Type = dto.Type,
            State = 0
        };
        if (dto.Card.HasValue)
            useDrawMoney.Card = dto.Card.Value;
        _drawMoneyRepository.Insert(useDrawMoney);
        return new AppResult();
    }
}